/*************************************************************************
 *  Copyright (C), 2017-2018, Mogoson tech. Co., Ltd.
 *  FileName: RayAreaRoam.cs
 *  Author: Mogoson   Version: 1.0   Date: 7/13/2017
 *  Version Description:
 *    Internal develop version,mainly to achieve its function.
 *  File Description:
 *    Ignore.
 *  Class List:
 *    <ID>           <name>             <description>
 *     1.          RayAreaRoam             Ignore.
 *  Function List:
 *    <class ID>     <name>             <description>
 *     1.
 *  History:
 *    <ID>    <author>      <time>      <version>      <description>
 *     1.     Mogoson     7/13/2017       1.0        Build this file.
 *************************************************************************/

namespace Developer.AreaRoam
{
    using AnimationCurve;
    using System.Collections;
    using UnityEngine;

    [AddComponentMenu("Developer/AreaRoam/RayAreaRoam")]
    public class RayAreaRoam : AreaRoam
    {
        #region Property and Field
        /// <summary>
        /// LayerMask of ray.
        /// </summary>
        public LayerMask layerMask = 1;

        /// <summary>
        /// Radius of sphere cast.
        /// </summary>
        public float radius = 0.5f;

        /// <summary>
        /// Ray space of check path curve.
        /// </summary>
        protected float raySpace = 0.5f;
        #endregion

        #region Protected Method
        protected override void OnDrawGizmosSelected()
        {
            Gizmos.color = new Color(0, 1, 1, 0.5f);
            Gizmos.DrawSphere(transform.position, radius);

            base.OnDrawGizmosSelected();
        }

        /// <summary>
        /// Extend path curve.
        /// </summary>
        protected override IEnumerator ExtendCurve()
        {
            //Initialise curve.
            var lastPoint = transform.position;
            curve = new VectorAnimationCurve();
            curve.AddKey(0, lastPoint);

            //Extend curve.
            while (true)
            {
                if (curve.length < maxLength)
                {
                    var loop = true;
                    while (loop)
                    {
                        var newPoint = area.GetPoint();
                        if (newPoint == lastPoint)
                        {
                            yield return new WaitForSeconds(Time.deltaTime);
                            continue;
                        }

                        var distance = Vector3.Distance(lastPoint, newPoint);
                        curve.AddKey(curve[curve.length - 1].time + distance, newPoint);
                        if (SphereCastCheck(curve, curve.length - 2))
                        {
                            curve.RemoveKey(curve.length - 1);
                            yield return new WaitForSeconds(Time.deltaTime);
                        }
                        else
                        {
                            lastPoint = newPoint;
                            loop = false;
                        }
                    }
                }
                yield return new WaitForSeconds(Time.deltaTime);
            }
        }

        /// <summary>
        /// SphereCast to check if something on curve path.
        /// </summary>
        /// <param name="curve">Check target.</param>
        /// <param name="startFrame">Start index of key frame.</param>
        /// <returns>Is something on curve path.</returns>
        protected bool SphereCastCheck(VectorAnimationCurve curve, int startFrame = 0)
        {
            var maxTime = curve[curve.length - 1].time;
            for (float t = curve[startFrame].time; t < maxTime; t += raySpace)
            {
                var point = curve.Evaluate(t);
                var tangent = curve.Evaluate(Mathf.Min(t + raySpace, maxTime)) - point;
                var ray = new Ray(point, tangent.normalized);
                if (Physics.SphereCast(ray, radius, tangent.magnitude, layerMask))
                    return true;
            }
            return false;
        }
        #endregion
    }//class_end
}//namespace_end